﻿using Devonline.AspNetCore;
using Devonline.Identity.Admin.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;

namespace Devonline.Identity.Admin.Controllers
{
    /// <summary>
    /// 资源管理
    /// </summary>    
    [Route("api/[controller]")]
    [SecurityHeaders]
    [ApiController]
    [Authorize]
    public class ResourcesController : ControllerBase
    {
        private readonly string _userName;
        private readonly ILogger<ResourcesController> _logger;
        private readonly ResourceAccessStore _resourceAccessStore;
        private readonly IDataWithAttachmentService<IdentityDbContext, Resource> _dataService;
        private static CancellationToken CancellationToken => CancellationToken.None;

        public ResourcesController(
            ILogger<ResourcesController> logger,
            ResourceAccessStore resourceAccessStore,
            IDataWithAttachmentService<IdentityDbContext, Resource> dataService)
        {
            _userName = User.Identity.Name;
            _logger = logger;
            _resourceAccessStore = resourceAccessStore;
            _dataService = dataService;
        }

        /// <summary>
        /// 查询资源
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [EnableQuery]
        public IActionResult Get()
        {
            _logger.LogInformation("user {user} query the resource list", _userName);
            return Ok(_dataService.GetQueryable());
        }
        /// <summary>
        /// 创建资源
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> CreateAsync(ResourceViewModel viewModel)
        {
            _logger.LogInformation("user {user} will add the resource {resource}", _userName, viewModel.Name);

            try
            {
                viewModel.OwnerId = HttpContext.GetUserId();
                viewModel.IdentityType = IdentityType.User;
                var resource = await _dataService.AddAsync(viewModel);
                _logger.LogWarning("user {user} success to add the resource {resource}", _userName, viewModel.Name);
                return Ok(resource);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "user {user} add the group {group} throw exception", _userName, viewModel.Name);
            }

            return BadRequest($"新增资源 {viewModel.Name} 没有成功!");
        }
        /// <summary>
        /// 修改资源
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task<IActionResult> ChangeAsync(ResourceChangeViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource}", _userName, viewModel.Name);

            try
            {
                var group = await _dataService.UpdateAsync(viewModel);
                _logger.LogWarning("user {user} success to add the group {group}", _userName, viewModel.Name);
                return Ok(group);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "user {user} add the group {group} throw exception", _userName, viewModel.Name);
            }

            return BadRequest($"修改资源 {viewModel.Name} 没有成功!");
        }
        /// <summary>
        /// 修改资源父级
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("ChangeParent")]
        public async Task<IActionResult> ChangeParentAsync(ChangeParentViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource} parent to {parent}", _userName, viewModel.Id, viewModel.ParentId);
            var resource = await _dataService.GetAsync(viewModel.Id);
            if (resource == null)
            {
                return NotFound();
            }

            try
            {
                await _resourceAccessStore.SetParent(resource, viewModel.ParentId);
                _dataService.Update(resource);
                await _dataService.SaveChangesAsync();
                _logger.LogWarning("user {user} success to change the resource {resource} parent to {parent}", _userName, resource.Name, viewModel.ParentId);
                return Ok();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "user {user} change the resource {resource} parent to {parent} throw exception", _userName, resource.Name, viewModel.ParentId);
            }

            return BadRequest($"修改资源 {resource.Name} 父级没有成功!");
        }
        /// <summary>
        /// 修改资源所有者
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("ChangeOwner")]
        public async Task<IActionResult> ChangeOwnerAsync(ChangeOwnerViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource} owner to {owner} and owner type to {ownerType}", _userName, viewModel.Id, viewModel.OwnerId, viewModel.IdentityType);
            var resource = await _dataService.GetAsync(viewModel.Id);
            if (resource == null)
            {
                return NotFound();
            }
            try
            {
                await _resourceAccessStore.SetOwner(resource, viewModel.OwnerId);
                _dataService.Update(resource);
                await _dataService.SaveChangesAsync();
                _logger.LogWarning("user {user} success to change the resource {resource} owner to {owner} and owner type to {ownerType}", _userName, resource.Name, viewModel.OwnerId, viewModel.IdentityType);
                return Ok();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "user {user} change the resource {resource} owner to {owner} and owner type to {ownerType} throw exception", _userName, resource.Name, viewModel.OwnerId, viewModel.IdentityType);
            }

            return BadRequest($"修改资源 {resource.Name} 所有者没有成功!");
        }
        /// <summary>
        /// 修改资源可访问级别
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("ChangeLevel")]
        public async Task<IActionResult> ChangeLevelAsync(ResourceChangeLevelViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource} level to {level} and access level to {accessLevel}", _userName, viewModel.Id, viewModel.LevelName, viewModel.AccessLevel);
            var resource = await _dataService.GetAsync(viewModel.Id);
            if (resource == null)
            {
                return NotFound();
            }
            try
            {
                await _resourceAccessStore.SetLevel(resource, viewModel.LevelName, CancellationToken);
                await _resourceAccessStore.SetAccessLevel(resource, viewModel.AccessLevel, CancellationToken);
                _dataService.Update(resource);
                await _dataService.SaveChangesAsync();
                _logger.LogWarning("user {user} success to change the resource {resource} level to {level} and access level to {accessLevel}", _userName, resource.Name, viewModel.LevelName, viewModel.AccessLevel);
                return Ok();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "user {user} change the resource {resource} level to {level} and access level to {accessLevel} throw exception", _userName, resource.Name, viewModel.LevelName, viewModel.AccessLevel);
            }

            return BadRequest($"修改资源 {resource.Name} 级别没有成功!");
        }

        /// <summary>
        /// 删除(逻辑删除)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteAsync(string id)
        {
            try
            {
                _logger.LogInformation("user {user} will remove the resource {resource}", _userName, id);
                await _dataService.DeleteAsync(id);
                _logger.LogWarning("user {user} success to remove the resource {resource}", _userName, id);
                return Ok();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "user {user} remove the resource {resource} throw exception", _userName, id);
            }

            return BadRequest($"删除资源 {id} 出错!");
        }
    }
}
